home *** CD-ROM | disk | FTP | other *** search
/ CD World 1998 January / CD World - Ocak 1998.iso / misc / dbase55 / disk7 / extern.pak / DBFILE.CPP < prev    next >
C/C++ Source or Header  |  1996-01-05  |  23KB  |  863 lines

  1. //****************************************************************************
  2. //
  3. // FILE:        DBFile.cpp
  4. //
  5. // WRITTEN BY:  Keimpe
  6. //
  7. // DATE:        1/94
  8. //
  9. // UPDATED:     5/95
  10. //
  11. // REVISION:    $Revision:   2.12  $
  12. //
  13. // VERSION:     Visual dBASE
  14. //
  15. // DESCRIPTION:
  16. //
  17. // Main source file for dbfile, a Visual dBASE example.
  18. //
  19. // This example implements a series of textfile manipulation routines. These
  20. // routines are accessible from Visual dBASE through the EXTERN system.
  21. // A Textfile object on the Visual dBASE side initiates the contact by creating
  22. // a corresponding C++ Textfile object through a call to TFinit which
  23. // returns a pointer to that C++ object to the Visual dBASE object.  After that
  24. // the Visual dBASE object can call into this DLL for specific routines.  The
  25. // C++ routine calls back to the Visual dBASE object through DBase->GetThis()
  26. // to get the this pointer of the corresponding C++ object and calls
  27. // the wanted memberfunction of that object.
  28. //
  29. // Right now the available routines are:
  30. //     close               - closes the current file if any.
  31. //     eof                 - helps detect EOF.
  32. //     error               - tells if an error was encountered.
  33. //     fieldseparator      - sets the field separator.
  34. //     filter              - sets the filter string.
  35. //     geterror            - returns the last error encountered if any.
  36. //     getfield            - gets the next field of the current record.
  37. //     getline             - gets the next line.
  38. //     getrec              - gets the next record.
  39. //     lineseparator       - sets the line separator.
  40. //     open                - opens a file.
  41. //     release             - releases the C++ object.
  42. //
  43. // A line is ended by a lineseparator or EOF. If you add a '+' char
  44. // to the char you send to "SetLineSeparator" it is assumed that
  45. // the lineseparator is one or more char's of that lineseparator.
  46. // A rec is a line that contains fields. Getrec sets up the fields
  47. // and returns the number of fields in the current rec. A field is
  48. // surrounded by one or more field separators including as special
  49. // cases the start and the end of a line.
  50. // If the filter is set a getline or getrec will search till
  51. // a line is found that contains the filter string as a substring.
  52. //
  53. // The file dbfile.h will give a quick idea of how the C++ class is
  54. // set up. The file dbfile.prg will tell you how things work on the
  55. // Visual dBASE side.  The file dbasevar.h deals with the basic classes
  56. // that ease the communication between C++ and Visual dBASE.
  57. //
  58. //****************************************************************************
  59.  
  60.    // Get the header.
  61. #include "dbfile.h"
  62.  
  63.    // If you want to test the TextFile C++ class under DOS, define DOSTEST.
  64.    // This will isolate the class from any Windows and Visual dBASE details and
  65.    // allows this file to be compiled and linked with DOS programs.
  66. #ifndef DOSTEST
  67.  
  68. //============================================================================
  69. //
  70. //  You can create an instance of class CSession in DBaseInitInstance()
  71. //  and set it up. In subsequent call backs, a pointer to this instance
  72. //  can be retrieved with a call to GetSession().  Data that is kept on
  73. //  a per-instance basis (DBaseVars for example) should be kept in the
  74. //  session object.
  75. //
  76. //============================================================================
  77.  
  78. class CSession {
  79. public:
  80.  
  81.    // Local objects.
  82.  
  83.    CSession(){
  84.        // Initialize objects local to this session.
  85.    }
  86.    ~CSession(){
  87.        // Destroy objects local to this session.
  88.    }
  89.  
  90.    // Memberfunctions to use local objects.
  91. };
  92.  
  93.  
  94. extern "C" {
  95.  
  96. //============================================================================
  97. //
  98. //  Usual DLL functions.
  99. //
  100. //============================================================================
  101.  
  102. int FAR PASCAL LibMain(HINSTANCE, WORD, WORD, LPSTR){
  103.  
  104.    return 1;
  105. }
  106. int CALLBACK WEP(int /*nParam*/){return(1);}
  107.  
  108. //
  109. //  This function is called every time an Instance of Visual dBASE loads the DLL.
  110. //  If for some reason the DLL determines that it cannot load, it can return
  111. //  an error.  If the DLL loads properly it should return DBASE_INIT_OK.
  112. //
  113.  
  114. int CALLBACK DBaseInitInstance(void){
  115.  
  116.    asm int 3;     // break point for the debugger.
  117.  
  118.    DBase()->SetSession(new CSession());
  119.  
  120.        //
  121.        // Possible Error return Values
  122.        //
  123.        //return DBASE_INIT_NO_MULTI_INSTANCE;
  124.        //return DBASE_INIT_ERROR;
  125.  
  126.    return DBASE_INIT_OK;
  127. }
  128.  
  129. //
  130. //  DBaseExitInstance() is called when an instance of Visual dBASE terminates or
  131. //  manually unloads a DLL through the RELEASE DLL command.  This give the
  132. //  DLL a chance to free any resources associated with a running instance.
  133. //
  134.  
  135. void CALLBACK DBaseExitInstance(void){
  136. }
  137.  
  138.    // End of DOSTEST define
  139. #endif
  140.  
  141. //============================================================================
  142. //
  143. // Implementation of memberfunctions of the TextFile class.
  144. //
  145. //============================================================================
  146.  
  147.    // Some common defines.
  148. #define LINE  0
  149. #define REC   1
  150.  
  151. //
  152. // AddToText( char*, char * ).
  153. //
  154. // Helper function to append a char string to the Text string. The
  155. // Text buffer grows as needed to fit the largest rec or line
  156. // encountered in the file.
  157. //
  158. // Returns 1 on success, 0 on error.
  159. //
  160.  
  161. BOOL TextFile::AddToText( char * Begin, char * End ) {
  162.  
  163.    unsigned int Len;
  164.    char SaveIt = *End;
  165.  
  166.        // Zero terminate the incoming string.
  167.    *End = 0x0;
  168.    Len = strlen( Begin );
  169.  
  170.        // See if we need more room.
  171.    if( (TextLen + Len) > MaxTextLen ) {
  172.        char * NewText;
  173.  
  174. #ifdef NO_EXCEPTIONS
  175.  
  176.        MaxTextLen = TextLen + Len;
  177.        NewText = new char[ MaxTextLen + 1 ];
  178.        if( NewText != NULL ) {
  179.            strcpy( NewText, Text );
  180.            delete [] Text;
  181.            Text = NewText;
  182.        }
  183.        else {
  184.                // Must be something wrong.
  185.            Text[0] = 0x0;
  186.            TextLen = 0;
  187.            *End = SaveIt;
  188.            return 0;
  189.        }
  190.  
  191. #else  // NO_EXCEPTIONS
  192.  
  193.        try {
  194.            MaxTextLen = TextLen + Len;
  195.            NewText = new char[ MaxTextLen + 1 ];
  196.            strcpy( NewText, Text );
  197.            delete [] Text;
  198.            Text = NewText;
  199.        }
  200.        catch(...) {
  201.  
  202.                // Must be something wrong.
  203.            Text[0] = 0x0;
  204.            TextLen = 0;
  205.            *End = SaveIt;
  206.            return 0;
  207.        }
  208.  
  209. #endif  // NO_EXCEPTIONS
  210.  
  211.    }
  212.        // Now simply copy it in.
  213.    strcpy( Text + TextLen, Begin );
  214.    TextLen += Len;
  215.  
  216.        // Restore.
  217.    *End = SaveIt;
  218.  
  219.        // Return success.
  220.    return 1;
  221. }
  222.  
  223. //
  224. // Close().
  225. //
  226. // Closes the file and sets Handle to 0.
  227. //
  228. // Returns 1 on success, 0 on error.
  229. //
  230.  
  231. BOOL TextFile::Close() {
  232.  
  233.    if( Handle != 0 )
  234.        if( close( Handle ) != 0 )
  235.            return 0;
  236.  
  237.    Handle = 0;
  238.  
  239.        // return success.
  240.    return 1;
  241. }
  242.  
  243. //
  244. // GetField( int ).
  245. //
  246. // This returns a pointer to the field specified by the WhichField
  247. // parameter.  The fields are contained inside a rec separated by
  248. // single fieldseparators.  When you send a field away, you simply insert
  249. // a zero at the end of that field.  Next time you come back here you
  250. // put that separator back which you can always find as the first char
  251. // of the Text buffer.
  252. //
  253. // Returns pointer to field, or pointer to empty string in case of error.
  254. //
  255.  
  256. char * TextFile::GetField( int WhichField ) {
  257.  
  258.    char *FieldStart = Text + 1, *FieldEnd = Text + 1, Separator = Text[0];
  259.  
  260.        // First see if we have to reinsert the end of a previous
  261.        // field we sent away.
  262.    if( SaveFieldEndPtr != NULL ) {
  263.        *SaveFieldEndPtr = Text[0];
  264.        SaveFieldEndPtr = NULL;
  265.    }
  266.  
  267.        // Check if we have the field at all.
  268.    if( WhichField <= 0 || WhichField > NumberOfFields )
  269.        return "";
  270.  
  271.        // Find the field in the Text buffer.
  272.    while( --WhichField > 0 ) {
  273.        FieldStart = strchr( FieldStart, Separator );
  274.        if( FieldStart == NULL ) {
  275.            strcpy( ErrorString, "Record corrupted" );
  276.            return "";
  277.        }
  278.        FieldStart++;
  279.    }
  280.  
  281.        // Find the end and mark it.
  282.    FieldEnd = strchr( FieldStart, Separator );
  283.    if( FieldEnd != NULL ) {
  284.        SaveFieldEndPtr = FieldEnd;
  285.        *FieldEnd = 0x0;
  286.    }
  287.  
  288.        // Send it away.
  289.    return FieldStart;
  290. }
  291.  
  292.  
  293. //
  294. // Open( char* ).
  295. //
  296. // If a file was already open, that file is closed before the
  297. // requested file is opened.  Handle is set to the file.
  298. //
  299. // Returns 1 on success, 0 on error.
  300. //
  301.  
  302. BOOL TextFile::Open( char *FileToOpen ) {
  303.  
  304.       // Is there already a file open.
  305.       // If so, close it. Check for proper return.
  306.    if( Handle != 0 )
  307.       if( close( Handle ) != 0 )
  308.          return 0;
  309.  
  310.       // Now open the file requested. Check for valid pointer return.
  311.    if( ( Handle = open( FileToOpen, O_RDONLY | O_TEXT ) ) == -1 )
  312.       return 0;
  313.  
  314.        // Start a new errorstring. Set up the Buffer.
  315.    ErrorString[ 0 ] = 0x0;
  316.    BufPtr = Buffer;
  317.    Buffer[ 0 ] = 0x0;
  318.  
  319.       // Return success.
  320.    return 1;
  321. }
  322.  
  323. //
  324. // ReadNextItem( char ).
  325. //
  326. // Reads the next item, either a line or a rec as indicated by the
  327. // LineOrRec parameter, into the Text character buffer.  The file
  328. // is buffer by buffer read into Buffer.  Buffer is scanned for
  329. // separators and EOF.  After a field separator is found we handle
  330. // field details if we're reading a rec.  After we find a line separator
  331. // the BufPtr is set to after the separator for the next readitem.
  332. // The Buffer is flushed into the Text buffer after each field and
  333. // line or when the Buffer runs out.  At the end a complete next
  334. // line or rec will be in the Text buffer.
  335. //
  336. // Returns Text on success, "" on error.
  337. //
  338.  
  339. char * TextFile::ReadNextItem( char LineOrRec ) {
  340.  
  341.    char Done, Found = 0, StartOfRec;
  342.    unsigned int NumberOfBytes;
  343.    char BothSeparators[3] = { LineSeparator, 0x0, 0x0 };
  344.    char * SepPtr = NULL, SepFound = 0x0;
  345.  
  346.        // In error state?
  347.    if( Error() )
  348.        return "";
  349.  
  350.        // Are we in business already?
  351.    if( Handle == 0 ) {
  352.        strcpy( ErrorString, "No file open\n" );
  353.        return "";
  354.    }
  355.  
  356.        // If we're scanning for a rec, we need the fieldseparator.
  357.    if( LineOrRec == REC )
  358.        BothSeparators[1] = FieldSeparator;
  359.  
  360.        // Keep reading till we found the next item.
  361.    while( !Found ) {
  362.  
  363.            // Set up for the search and initialize Text.
  364.        Done = 0;
  365.        Text[0] = 0x0;
  366.        TextLen = 0;
  367.        NumberOfFields = 0;
  368.        SaveFieldEndPtr = NULL;
  369.        StartOfRec = (LineOrRec == REC );
  370.  
  371.            // Read and scan till we find a separator or EOF.
  372.        while( !Done ) {
  373.  
  374.                // Did we run out of chars in the Buffer.
  375.            if( *BufPtr == 0x0 ) {
  376.  
  377.                    // Read in a buffer full.
  378.                NumberOfBytes = (unsigned int) read( Handle,
  379.                                                     Buffer, BUFFERLENGTH );
  380.  
  381.                    // Check for EOF or error.
  382.                if( NumberOfBytes == (unsigned int) -1 ||
  383.                    NumberOfBytes == 0 ) {
  384.                    if( NumberOfBytes != 0 ) {
  385.                        strcpy( ErrorString, "Error Reading\n" );
  386.                        return "";   // Error.
  387.                    }
  388.                    Done = 1;        // EOF.
  389.  
  390.                        // If there's nothing in the textbuffer we
  391.                        // can't find a next item.
  392.                    if( Text[0] == 0x0 ) {
  393.                        Found = 1;
  394.                    }
  395.                        // But if there is something check if we have
  396.                        // the last field of the file that we haven't
  397.                        // counted yet.
  398.                    else if( LineOrRec == REC && SepFound == 0x0 )
  399.                        NumberOfFields++;
  400.  
  401.                    continue;
  402.                }
  403.  
  404.                    // Set up for the search.
  405.                BufPtr = Buffer;
  406.                *( BufPtr + NumberOfBytes ) = 0x0;
  407.                CopyPtr = Buffer;
  408.            }
  409.  
  410.                // If we scan for a REC, first eat any fieldseparators
  411.                // at the beginning. If we run out of Buffer, fall
  412.                // through and read more. We also put the current
  413.                // fieldseparator as the first char of the Text.
  414.            if( StartOfRec == 1 ) {
  415.  
  416.                while( *BufPtr == FieldSeparator )
  417.                    BufPtr++;
  418.                if( *BufPtr == 0x0 )
  419.                    continue;
  420.  
  421.                StartOfRec = 0;
  422.                Text[ 0 ] = FieldSeparator;
  423.                TextLen++;
  424.                CopyPtr = BufPtr;
  425.            }
  426.  
  427.                // Look for the next separator IF we're not already
  428.                // inside a separator.
  429.            if( SepFound == 0x0 ) {
  430.  
  431.                    // Cruise till we find a separator.
  432.                SepPtr = strpbrk( BufPtr, BothSeparators );
  433.  
  434.                    // If we found a separator.
  435.                if( SepPtr != NULL ) {
  436.  
  437.                        // Mark the end.
  438.                    BufPtr = SepPtr;
  439.                    SepFound = *SepPtr;
  440.  
  441.                        // If we are looking for fields.
  442.                    if( LineOrRec == REC ) {
  443.  
  444.                            // Increase number of fields. Send one
  445.                            // fieldseparator to text as well IF
  446.                            // we found a fieldseparator.
  447.                        NumberOfFields++;
  448.                        if( SepFound == FieldSeparator )
  449.                            BufPtr++;
  450.                    }
  451.                }
  452.                else {  // We did not find a separator. Adjust BufPtr.
  453.  
  454.                    BufPtr += strlen( BufPtr );
  455.                }
  456.  
  457.                    // Add what we have to Text.
  458.                if( AddToText( CopyPtr, BufPtr ) == 0 ) {
  459.  
  460.                        // Error occured.
  461.                    strcpy( ErrorString, "Line/Field too long" );
  462.                    return "";
  463.                }
  464.            }
  465.  
  466.                // If we found a separator ( or are inside a separator ).
  467.            if( SepFound != 0x0 ) {
  468.  
  469.                    // If we found a lineseparator and only singles of
  470.                    // those are allowed, simply skip one and continue.
  471.                if( SepFound == LineSeparator && PlusLineSeparator == 0 ) {
  472.                    BufPtr++;
  473.                    SepFound = 0x0;
  474.                    Done = 1;
  475.                    CopyPtr = BufPtr;
  476.                    continue;
  477.                }
  478.  
  479.                    // Now we scan till we run out of separators.
  480.                while( *BufPtr == SepFound )
  481.                    BufPtr++;
  482.  
  483.                    // If we found the end of the buffer, fall
  484.                    // through and continue reading.
  485.                if( *BufPtr == 0x0 )
  486.                    continue;
  487.  
  488.                    // Special case for when we found a lineseparator
  489.                    // after a bunch of fieldseparators. Means we have
  490.                    // to fall through and scan for the end of the rec.
  491.                if( *BufPtr == LineSeparator ) {
  492.                    SepFound = LineSeparator;
  493.                    continue;
  494.                }
  495.  
  496.                    // We're done IF we were looking for lineseparator(s).
  497.                if( SepFound == LineSeparator )
  498.                    Done = 1;
  499.  
  500.                    // Either way, we're done with the separator found.
  501.                    // And we can adjust copyptr.
  502.                SepFound = 0x0;
  503.                CopyPtr = BufPtr;
  504.            }
  505.        }
  506.  
  507.            // Now see if a filter is in place.
  508.        if( Filter[0] != 0x0 ) {
  509.            if( strstr( Text, Filter ) != NULL )
  510.                Found = 1;
  511.        }
  512.        else {
  513.                // Otherwise we have found what we wanted.
  514.            Found = 1;
  515.        }
  516.    }
  517.  
  518.        // Return success.
  519.    return Text;
  520. }
  521.  
  522. //
  523. // SetFilter( char* ).
  524. //
  525. // Sets the Filter char string. ReadNextItem only returns the next
  526. // item IF it contains the Filter string as a substring.
  527. // Can be called with SetFilter( "" ) to set the filter to nothing.
  528. //
  529. // Returns 1 on success. 0 on error.
  530. //
  531.  
  532. BOOL TextFile::SetFilter( char *InFilter ) {
  533.  
  534.    unsigned int Len = strlen( InFilter );
  535.  
  536.        // If there's enough room, copy it in and leave.
  537.    if( Len <= FilterLen ) {
  538.        strcpy( Filter, InFilter );
  539.        return 1;
  540.    }
  541.        // Not enough room, start with a clean slate.
  542.    delete [] Filter;
  543.  
  544.        // Create some room.
  545.  
  546. #ifdef NO_EXCEPTIONS
  547.  
  548.    Filter = new char [ Len + 1 ];
  549.    if( Filter != NULL ){
  550.        FilterLen = Len;
  551.    }
  552.    else {
  553.            // Guess not.
  554.        strcpy( ErrorString, "Filter too long" );
  555.        FilterLen = 0;
  556.        return 0;
  557.    }
  558.  
  559. #else // NO_EXCEPTIONS
  560.  
  561.    try {
  562.        Filter = new char [ Len + 1 ];
  563.        FilterLen = Len;
  564.    }
  565.    catch(...) {
  566.            // Guess not.
  567.        strcpy( ErrorString, "Filter too long" );
  568.        FilterLen = 0;
  569.        return 0;
  570.    }
  571.  
  572. #endif // NO_EXCEPTIONS
  573.  
  574.    strcpy( Filter, InFilter );
  575.  
  576.        // Success.
  577.    return 1;
  578. }
  579.  
  580. //
  581. // SetFieldSeparator( char * ).
  582. //
  583. // Sets the fieldseparator char.
  584. //
  585. // Returns 1 on success, 0 on error.
  586. //
  587.  
  588. BOOL TextFile::SetFieldSeparator( char *Separator ) {
  589.  
  590.        // If nothing there, ignore, but return error.
  591.    if( Separator == NULL )
  592.        return 0;
  593.  
  594.        // Set the FieldSeparator.
  595.    FieldSeparator = *Separator;
  596.  
  597.        // We did it.
  598.    return 1;
  599. }
  600.  
  601. //
  602. // SetLineSeparator( char * ).
  603. //
  604. // Sets the lineseparator char. If the second char of the incoming
  605. // string is a '+' it is assumed that the separator is multiples of
  606. // the lineseparator char.
  607. //
  608. // ASSUMES a string is sent over, not a single character!!
  609. //
  610. // Returns 1 on success, 0 on error.
  611. //
  612.  
  613. BOOL TextFile::SetLineSeparator( char *Separator ) {
  614.  
  615.        // If nothing there, ignore, but return error.
  616.    if( Separator == NULL )
  617.        return 0;
  618.  
  619.        // Set the LineSeparator and PlusLineSeparator if needed.
  620.    LineSeparator = *Separator;
  621.    if( *(Separator+1) == '+' )
  622.        PlusLineSeparator = 1;
  623.    else
  624.        PlusLineSeparator = 0;
  625.  
  626.        // We did it.
  627.    return 1;
  628. }
  629.  
  630.    // If you want to test the C++ class under DOS, define DOSTEST.
  631. #ifndef DOSTEST
  632.  
  633. //============================================================================
  634.  
  635. //
  636. // TextFile routines called from the Visual dBASE side.
  637. //
  638.  
  639. //============================================================================
  640.  
  641. //
  642. // GetCPlusPlusThis().
  643. //
  644. // Helper function to get the C++ this pointer out of the Visual dBASE object.
  645. //
  646. // Returns a TextFile pointer.
  647. //
  648.  
  649. TextFile* GetCPlusPlusThis() {
  650.  
  651.        // Local vars. Get the this of the Visual dBASE object.
  652.    DVar CThis, DBaseThis( DBase()->GetThis() );
  653.  
  654.        // Get the this of the corresponding C++ object.
  655.    DBaseThis->Property( "MYSTRUCT", CThis );
  656.  
  657.    return (TextFile*)(CThis->Long());
  658. }
  659.  
  660. //
  661. // TFclose().
  662. //
  663. // Closes the file.
  664. //
  665. // Returns 1 on success, 0 on error.
  666. //
  667.  
  668. BOOL _export _pascal TFclose() {
  669.  
  670.    return GetCPlusPlusThis()->Close();
  671. }
  672.  
  673. //
  674. // TFeof().
  675. //
  676. // Returns 1 on EOF, 0 otherwise.
  677. //
  678.  
  679. BOOL _export _pascal TFeof() {
  680.  
  681.    return GetCPlusPlusThis()->Eof();
  682. }
  683.  
  684. //
  685. // TFerror().
  686. //
  687. // Returns 1 on error set, 0 otherwise.
  688. //
  689.  
  690. BOOL _export _pascal TFerror() {
  691.  
  692.    return GetCPlusPlusThis()->Error();
  693. }
  694.  
  695. //
  696. // TFfilter( char* ).
  697. //
  698. // Sets the filter.
  699. //
  700. // Returns 1 on success, 0 on error.
  701. //
  702.  
  703. BOOL _export _pascal TFfilter( char * Filter ) {
  704.  
  705.    return GetCPlusPlusThis()->SetFilter( Filter );
  706. }
  707.  
  708. //
  709. // TFfieldseparator( char* ).
  710. //
  711. // Sets the fieldseparator char.
  712. //
  713. // Returns 1 on success, 0 on error.
  714. //
  715.  
  716. BOOL _export _pascal TFfieldseparator( char *InString ) {
  717.  
  718.    return GetCPlusPlusThis()->SetFieldSeparator( InString );
  719. }
  720.  
  721. //
  722. // TFgeterror().
  723. //
  724. // Returns pointer to the errorstring of the object.
  725. //
  726.  
  727. char * _export _pascal TFgeterror() {
  728.  
  729.    return GetCPlusPlusThis()->GetErrorString();
  730. }
  731.  
  732. //
  733. // TFgetfield( int ).
  734. //
  735. // Returna a pointer to the field as indicated by the parameter.
  736. //
  737. // Returns pointer to a field on success, "" on error.
  738. //
  739.  
  740. char * _export _pascal TFgetfield( int WhichField ) {
  741.  
  742.    return GetCPlusPlusThis()->GetField( WhichField );
  743. }
  744.  
  745. //
  746. // TFgetrec()
  747. //
  748. // Returns # of fields in the next rec on success, 0 on error or EOF.
  749. //
  750.  
  751. int _export _pascal TFgetrec() {
  752.  
  753.    TextFile * TFptr = GetCPlusPlusThis();
  754.    if( TFptr->ReadNextItem( REC ) != NULL )
  755.        return TFptr->GetNumberOfFields();
  756.    else
  757.        return 0;
  758. }
  759.  
  760. //
  761. // TFgetline().
  762. //
  763. // Returns pointer to the next line on success, "" on error or on EOF.
  764. //
  765.  
  766. char * _export _pascal TFgetline() {
  767.  
  768.    return GetCPlusPlusThis()->ReadNextItem( LINE );
  769. }
  770.  
  771. //
  772. // TFinit().
  773. //
  774. // Initialization routine called from Visual dBASE when the Visual dBASE
  775. // textfile object gets created.
  776. //
  777. // Return pointer (cast to a long) to a C++ TextFile object on success,
  778. // 0 on error.
  779. //
  780.  
  781. long _export _pascal TFinit() {
  782.  
  783.    TextFile * ThisTextFile;
  784.  
  785. #ifdef NO_EXCEPTIONS
  786.  
  787.        // Get the this of the CTextFile to be used.
  788.    ThisTextFile = new TextFile;
  789.    if( ThisTextFile != NULL ) {
  790.  
  791.            // Return pointer cast to a long.
  792.        return (long) ThisTextFile;
  793.    }
  794.    else {
  795.  
  796.            // Failure.
  797.        return 0L;
  798.    }
  799.  
  800. #else  // NO_EXCEPTIONS
  801.  
  802.    try {
  803.  
  804.            // Get the this of the CTextFile to be used.
  805.        ThisTextFile = new TextFile;
  806.  
  807.            // Return pointer cast to a long.
  808.        return (long) ThisTextFile;
  809.    }
  810.    catch( ... ) {
  811.  
  812.            // Failure.
  813.        return 0L;
  814.    }
  815.  
  816. #endif  // NO_EXCEPTIONS
  817.  
  818. }
  819.  
  820. //
  821. // TFlineseparator( char* ).
  822. //
  823. // Sets the line separator char.
  824. //
  825. // Returns 1 on success, 0 on error.
  826. //
  827.  
  828. BOOL _export _pascal TFlineseparator( char *InString ) {
  829.  
  830.    return GetCPlusPlusThis()->SetLineSeparator( InString );
  831. }
  832.  
  833. //
  834. // TFopen( char* ).
  835. //
  836. // Opens a new file.
  837. //
  838. // Returns 1 on sucess, 0 on error.
  839. //
  840.  
  841. BOOL _export _pascal TFopen( char * FileToOpen ) {
  842.  
  843.    return GetCPlusPlusThis()->Open( FileToOpen );
  844. }
  845.  
  846. //
  847. // TFrelease().
  848. //
  849. // Releases the C++ TextFile object.
  850. //
  851. // Returns 1 on sucess, 0 on error.
  852. //
  853.  
  854. void _export _pascal TFrelease() {
  855.  
  856.    delete GetCPlusPlusThis();
  857. }
  858.  
  859. }  // extern "C"
  860.  
  861.    // End of DOSTEST define
  862. #endif
  863.